package net.skillkill.base;

import net.joke.base.EntityFactory;
import net.joke.base.components.AIComponent;
import net.joke.base.components.ActionQueue;
import net.joke.base.components.Effect;
import net.joke.base.components.Expires;
import net.joke.base.components.LocalPlayer;
import net.joke.base.components.Position;
import net.joke.base.components.Renderable;
import net.joke.base.components.SkillsComponent;
import net.joke.base.components.Stats;
import net.joke.base.components.sub.MoveTarget;
import net.joke.base.components.sub.SkillBase;
import net.joke.base.render.Explosion;
import net.joke.base.render.Hero;
import net.joke.base.render.Minion;
import net.joke.base.render.SpriteObjectData;
import net.joke.base.systems.InputSystem;

import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.sprite.BaseSprite;

import com.artemis.Entity;
import com.artemis.World;



/**
 * Classe singleton per generare le entity.
 * Diventa comodo riunire qui la creazione di OGNI tipo di entity che serve nel programma.
 * In questo modo possiamo sempre intervenire con comodo sulle eventuali logiche di creazione.
 * @author Gianluca
 *
 */
public class SkillKillEntityFactory {
	
	public static final String FACTION_1 = "F1";			// Player ed entity (mobiles) Local Player/side
	public static final String BULLET_FACTION_1 = "B1";		// Bullets (spell, arrows, ecc) Local Player/side
	public static final String FACTION_2 = "F2";			// Player ed entity (mobiles) AI-Remote/side
	public static final String BULLET_FACTION_2 = "B2";		// Bullets (spell, arrows, ecc) AI-Remote/side

	
	private static SkillKillEntityFactory instance;
	private SkillKillEntityFactory() {
		
	}
	public static synchronized SkillKillEntityFactory getInstance() {
		if (instance == null) {
			instance = new SkillKillEntityFactory();
		}
		return instance;
	}
	
	/** 
	 * Creo il player.<br>
	 * World serve per agganciare le entity<br>
	 * Scene serve per agganciare il Renderable (siamo in gestione AndEngine)<br>
	 * x ed y sono per preimpostare le coordinate di partenza.<br>
	 * @param world
	 * @param scene
	 * @param coordX
	 * @param coordY
	 * @return
	 */
	public Entity makePlayer(World world, Scene scene, float coordX, float coordY) {
		Entity rv =  world.createEntity();
		rv.setGroup(FACTION_1);
		
		// componente posizione
		rv.addComponent(new Position(coordX, coordY));
		// LocalPlayer (solo per la gestione dei system
		rv.addComponent(new LocalPlayer());
		// Renderable (lo sprite di AndEngine)
		rv.addComponent(new Renderable(new Hero(SkillKillRes.playerSprite(scene), scene)));
		// Action Queue
		rv.addComponent(new ActionQueue());
		// Stats
		Stats s = new Stats();
		s.baseStat.maxLife = 100;
		s.baseStat.currentLife = 100;
		s.baseStat.recoverHp = 10;
		s.baseStat.speed = 0.08f;
		s.isStatDirty = true;
		rv.addComponent(s);
		// N.B. chiamare SEMPRE entity.refresh() dopo un cambio di componenti
		rv.refresh();
		
		return rv;
	}
	
	public enum MinionPaths {
		TOP,
		MID,
		BOT
	};
	
	
	public Entity makeMinion01(World world, Scene scene, float coordX, float coordY, MinionPaths path, InputSystem inputSystem) {
		Entity rv =  world.createEntity();
		rv.setGroup(FACTION_2);
		
		// componente posizione
		rv.addComponent(new Position(coordX, coordY));
//		// LocalPlayer (solo per la gestione dei system
//		rv.addComponent(new LocalPlayer());
// Aggiungeremo un AiPlayer che mantiene le indicazioni dell'AI da usare		
		// Renderable (lo sprite di AndEngine)
		BaseSprite minionSprite = SkillKillRes.minion01Sprite(scene);
		minionSprite.setUserData(new SpriteObjectData(inputSystem, rv));
		rv.addComponent(new Renderable(new Minion(minionSprite, scene)));
		// Stats
		Stats s = new Stats();
		s.baseStat.maxLife = 50;
		s.baseStat.currentLife = 10;
		s.baseStat.recoverHp = 10;
		s.baseStat.speed = 0.05f;
		s.baseStat.hitSpeed = 10000; // One hit every second
		s.isStatDirty = true;
		rv.addComponent(s);
		// Gli va dato gia un path ?
		// Per ora lo metto qui, forse va spostato nell'AI in modo che sia lei a decidere dove andare. 
		MoveTarget m = new MoveTarget(coordX, coordY);
		if (path == MinionPaths.TOP) {
			// N.B. per essere veloce, la bag non garantisce l'ordine salvo aggiungere elementi a rovescio e usare la removeLast()
			m.addWayPoint(608, 608);
			m.addWayPoint(512, 128);
			m.addWayPoint(32, 32);
		} else if (path == MinionPaths.MID) {
			m.addWayPoint(608, 608);
			m.addWayPoint(32, 32);
		} else if (path == MinionPaths.BOT) {
			m.addWayPoint(608, 608);
			m.addWayPoint(128, 512);
			m.addWayPoint(32, 32);
		}
		m.removedByOthers = false;
		ActionQueue actionQueue = new ActionQueue();
		actionQueue.addAction(m);
		rv.addComponent(actionQueue);
		
		// AI
		rv.addComponent(new AIComponent(AIComponent.KIND_BASE));
		
		// Skills
		rv.addComponent(new SkillsComponent(new SkillBase(0, 250, true)));
		
		
		// N.B. chiamare SEMPRE entity.refresh() dopo un cambio di componenti
		rv.refresh();
		
		return rv;
	}

	
	public Entity makeBullet01(Entity owner, World world, Scene scene, float coordX, float coordY, MoveTarget target) {
		Entity rv =  world.createEntity();
		String faction = world.getGroupManager().getGroupOf(owner);
		if (FACTION_1.equals(faction))
			faction = BULLET_FACTION_1;
		else if (FACTION_2.equals(faction))
			faction = BULLET_FACTION_2;
		else 
			faction = "";
		rv.setGroup(faction);
		
		// componente posizione
		rv.addComponent(new Position(coordX, coordY));
		// Renderable (lo sprite di AndEngine)
		BaseSprite bulletSprite = SkillKillRes.bullet01Sprite(scene);
		rv.addComponent(new Renderable(new Minion(bulletSprite, scene)));

		ActionQueue actionQueue = new ActionQueue();
		actionQueue.addAction(target);
		rv.addComponent(actionQueue);
		
		rv.addComponent(new Effect(Effect.EFFECT_BULLET));
		// N.B. chiamare SEMPRE entity.refresh() dopo un cambio di componenti
		rv.refresh();
		
		return rv;
	}
	
	public Entity makeExplosion01(World world, Scene scene, float coordX, float coordY) {
		Entity rv =  world.createEntity();
		rv.setGroup(EntityFactory.EFFECTS);
		
		// componente posizione
		rv.addComponent(new Position(coordX, coordY));
		// Renderable (lo sprite di AndEngine)
		BaseSprite effectSprite = SkillKillRes.explosion01Sprite(scene);
		rv.addComponent(new Renderable(new Explosion(effectSprite, scene)));

		rv.addComponent(new Expires(600 /* 25 * 24 */));
		// N.B. chiamare SEMPRE entity.refresh() dopo un cambio di componenti
		rv.refresh();
		
		return rv;
	}
	
// Sta in EntityFactory della Lib	
//	public Entity greenPoints(World world, Scene scene, float coordX, float coordY, float points) {
//		Entity rv =  world.createEntity();
//		rv.setGroup("TEXTS");
//		
//		// componente posizione
//		rv.addComponent(new Position(coordX, coordY));
//		// componente Target
//		rv.addComponent(new MoveTarget(coordX, coordY - 50, Config.textShiftSpeed ));
//		// Expires, rimane visibile solo per x secondi
//		rv.addComponent(new Expires(Config.textLifeMsec));
//		// Renderable (lo sprite di AndEngine)
//		rv.addComponent(new Renderable(new TextRenderable(Res.greenText(scene, points, coordX, coordY), scene)));
//		
//		rv.refresh();
//		
//		return rv;
//	}
	
//	public Entity makeHudButton() {
//		
//	}
	
}
